﻿#region Using namespaces

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#endregion

namespace BOL.Apps.GeneNetworkBrowser.Analysis.SubNetwork
{
    public class SubNetworkEnumeration : IAnalysis
    {
        #region private variables

        private Network _source;
        private IEnumerable<Gene> _seeds;
        private int _minNodes;
        private int _maxNodes;

        #endregion

        #region Constructor

        public SubNetworkEnumeration(Network source, IEnumerable<Gene> seeds, int minNodes, int maxNodes)
        {
            this._name = "SubNetwork (Enumeration)";

            this._source = source;
            this._seeds = seeds;
            this._minNodes = minNodes;
            this._maxNodes = maxNodes;
        }

        #endregion

        #region Private methods

        private IEnumerable<Network> Enumerate()
        {
            IEnumerable<Relation> relations;
            var tempNetworks = new HashSet<Network>();
            Network tempNetwork1;

            foreach (var seed in _seeds)
            {
                relations = _source.Edges.Where(x => x.Source.Equals(seed) || x.Target.Equals(seed));
                foreach (var relation in relations)
                {
                    if (relation.Source == seed)
                        relation.Target.Visit();
                    else
                        relation.Source.Visit();

                    tempNetwork1 = new Network();
                    if (tempNetwork1.AddVerticesAndEdge(relation))
                        tempNetworks.Add(tempNetwork1);
                }
            }

            var subNetworks = new List<Network>();
            int depth = 2;
            while (depth <= _maxNodes)
            {
                if (depth >= _minNodes)
                    foreach (var tempNetwork2 in tempNetworks)
                        subNetworks.Add(tempNetwork2);

                Console.WriteLine("Depth: {0}, #Network: {1}", depth, tempNetworks.Count);
                tempNetworks = Extend(tempNetworks);

                depth++;
            }

            return subNetworks;
        }

        private HashSet<Network> Extend(HashSet<Network> tempNetworks)
        {
            var resultNetworks = new HashSet<Network>();
            Gene gene1, gene2;
            IEnumerable<Relation> relations;
            int prevVertexCount;

            int i = 0;
            foreach (var tempNetwork in tempNetworks)
            {
                Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++");
                Console.WriteLine("Temp network{0:0000}: {1} - {2}", i++, tempNetwork, tempNetwork.GetHashCode());

                gene1 = tempNetwork.Vertices.First(x => x.IsVisited);
                gene1.NeverVisit();

                relations = _source.Edges.Where(x => x.Source.Equals(gene1) || x.Target.Equals(gene1));
                prevVertexCount = tempNetwork.VertexCount;
                Network cloneNetwork = null;

                foreach (var relation in relations)
                    if (!tempNetwork.Edges.Contains(relation)) // internal/external extension
                    {
                        gene2 = (relation.Source.Equals(gene1)) ? relation.Target : relation.Source;
                        gene2.Visit();

                        cloneNetwork = tempNetwork.Clone();
                        cloneNetwork.AddVerticesAndEdge(relation);

                        if (prevVertexCount < cloneNetwork.VertexCount)
                            resultNetworks.Add(cloneNetwork);
                    }
            }

            return resultNetworks;
        }

        #endregion

        #region IAnalysis implementation

        private string _name;

        public string Name { get { return _name; } set { _name = value; } }

        public IResult Analyze()
        {
            var subNetworks = Enumerate();
            return new SubNetworkResult("Result: SubNetwork (Enum) Analysis", subNetworks);
        }

        #endregion
    }
}
